// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;

namespace System
{
    internal static class AppContextConfigHelper
    {
        internal static bool GetBooleanConfig(string switchName, bool defaultValue) =>
            AppContext.TryGetSwitch(switchName, out bool value) ? value : defaultValue;

        internal static bool GetBooleanConfig(string switchName, string envVariable, bool defaultValue = false)
        {
            string? str = Environment.GetEnvironmentVariable(envVariable);
            if (str != null)
            {
                if (str == "1" || bool.IsTrueStringIgnoreCase(str))
                {
                    return true;
                }
                if (str == "0" || bool.IsFalseStringIgnoreCase(str))
                {
                    return false;
                }
            }

            return GetBooleanConfig(switchName, defaultValue);
        }

        internal static bool GetBooleanComPlusOrDotNetConfig(string configName, string envVariable, bool defaultValue)
        {
            string? str = Environment.GetEnvironmentVariable("DOTNET_" + envVariable)
                ?? Environment.GetEnvironmentVariable("COMPlus_" + envVariable);

            if (str != null && str.StartsWith("0x", StringComparison.Ordinal))
            {
                str = str.Substring(2);
            }

            if (str != null
                && uint.TryParse(str, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out uint resultUnsigned))
            {
                return resultUnsigned != 0;
            }

            return GetBooleanConfig(configName, defaultValue);
        }

        internal static int GetInt32Config(string configName, int defaultValue, bool allowNegative = true)
        {
            try
            {
                object? config = AppContext.GetData(configName);
                int result = defaultValue;
                switch (config)
                {
                    case uint value:
                        result = (int)value;
                        break;
                    case string str:
                        if (str.StartsWith('0'))
                        {
                            if (str.Length >= 2 && str[1] == 'x')
                            {
                                result = Convert.ToInt32(str, 16);
                            }
                            else
                            {
                                result = Convert.ToInt32(str, 8);
                            }
                        }
                        else
                        {
                            result = int.Parse(str, NumberStyles.AllowLeadingSign, NumberFormatInfo.InvariantInfo);
                        }
                        break;
                    case IConvertible convertible:
                        result = convertible.ToInt32(NumberFormatInfo.InvariantInfo);
                        break;
                }
                return !allowNegative && result < 0 ? defaultValue : result;
            }
            catch (FormatException)
            {
                return defaultValue;
            }
            catch (OverflowException)
            {
                return defaultValue;
            }
        }

        internal static int GetInt32Config(string configName, string envVariable, int defaultValue, bool allowNegative = true)
        {
            string? str = Environment.GetEnvironmentVariable(envVariable);
            if (str != null)
            {
                try
                {
                    int result;
                    if (str.StartsWith('0'))
                    {
                        if (str.Length >= 2 && str[1] == 'x')
                        {
                            result = Convert.ToInt32(str, 16);
                        }
                        else
                        {
                            result = Convert.ToInt32(str, 8);
                        }
                    }
                    else
                    {
                        result = int.Parse(str, NumberStyles.AllowLeadingSign, NumberFormatInfo.InvariantInfo);
                    }

                    if (allowNegative || result >= 0)
                    {
                        return result;
                    }
                }
                catch (FormatException)
                {
                }
                catch (OverflowException)
                {
                }
            }

            return GetInt32Config(configName, defaultValue, allowNegative);
        }

        internal static int GetInt32ComPlusOrDotNetConfig(string configName, string envVariable, int defaultValue, bool allowNegative)
        {
            string? str = Environment.GetEnvironmentVariable("DOTNET_" + envVariable)
                ?? Environment.GetEnvironmentVariable("COMPlus_" + envVariable);

            if (str != null && str.StartsWith("0x", StringComparison.Ordinal))
            {
                str = str.Substring(2);
            }

            if (str != null
                && uint.TryParse(str, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out uint resultUnsigned))
            {
                int result = (int)resultUnsigned;
                if (allowNegative || result >= 0)
                {
                    return result;
                }
            }

            return GetInt32Config(configName, defaultValue, allowNegative);
        }

        internal static short GetInt16Config(string configName, short defaultValue, bool allowNegative = true)
        {
            try
            {
                object? config = AppContext.GetData(configName);
                short result = defaultValue;
                switch (config)
                {
                    case uint value:
                        {
                            result = (short)value;
                            if ((uint)result != value)
                            {
                                return defaultValue; // overflow
                            }
                            break;
                        }
                    case string str:
                        if (str.StartsWith("0x"))
                        {
                            result = Convert.ToInt16(str, 16);
                        }
                        else if (str.StartsWith('0'))
                        {
                            result = Convert.ToInt16(str, 8);
                        }
                        else
                        {
                            result = short.Parse(str, NumberStyles.AllowLeadingSign, NumberFormatInfo.InvariantInfo);
                        }
                        break;
                    case IConvertible convertible:
                        result = convertible.ToInt16(NumberFormatInfo.InvariantInfo);
                        break;
                }
                return !allowNegative && result < 0 ? defaultValue : result;
            }
            catch (FormatException)
            {
                return defaultValue;
            }
            catch (OverflowException)
            {
                return defaultValue;
            }
        }

        internal static short GetInt16Config(string configName, string envVariable, short defaultValue, bool allowNegative = true)
        {
            string? str = Environment.GetEnvironmentVariable(envVariable);
            if (str != null)
            {
                try
                {
                    short result;
                    if (str.StartsWith('0'))
                    {
                        if (str.Length >= 2 && str[1] == 'x')
                        {
                            result = Convert.ToInt16(str, 16);
                        }
                        else
                        {
                            result = Convert.ToInt16(str, 8);
                        }
                    }
                    else
                    {
                        result = short.Parse(str, NumberStyles.AllowLeadingSign, NumberFormatInfo.InvariantInfo);
                    }

                    if (allowNegative || result >= 0)
                    {
                        return result;
                    }
                }
                catch (FormatException)
                {
                }
                catch (OverflowException)
                {
                }
            }

            return GetInt16Config(configName, defaultValue, allowNegative);
        }

        internal static short GetInt16ComPlusOrDotNetConfig(string configName, string envVariable, short defaultValue, bool allowNegative)
        {
            string? str = Environment.GetEnvironmentVariable("DOTNET_" + envVariable)
                ?? Environment.GetEnvironmentVariable("COMPlus_" + envVariable);

            if (str != null && str.StartsWith("0x", StringComparison.Ordinal))
            {
                str = str.Substring(2);
            }

            if (str != null
                && ushort.TryParse(str, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out ushort resultUnsigned))
            {
                short result = (short)resultUnsigned;
                if (allowNegative || result >= 0)
                {
                    return result;
                }
            }

            return GetInt16Config(configName, defaultValue, allowNegative);
        }
    }
}
